package zisu.qgs.lambda.lambda;

import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * @Author: 蔡翔
 * @Date: 2019/10/2 21:52
 * @Version 1.0
 */
//总结 一句话：lambda表达式是一个匿名函数。
class Dog{
    private String name = "哮天犬";
    private Integer food = 10;
    // 静态方法和 成员方法 区别： 成员方法可以访问Dog 这个类的this指针，而静态方法不可以但是它在项目启动的时候可以直接载入内存
    public static void bark(Dog dog) { // 输入的是Dog实例，输出的是空的。
        System.out.println(dog+"叫了");
    }

    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                '}';
    }

    // 这是一个非静态 方法，即成员方法的引用。
    public int eat(Dog this,int num){
        // 之所以 成员方法可以访问this指针，是因为jdk默认把这个指针传进去的。就相当于eat(Dog this,int num)
        // JDk 默认会把当前实例传入到非静态方法，参数名为 this，位置是第一个
        System.out.println("吃了："+num+"斤狗粮");
        this.food -=num;
        return this.food;
    }
    public Dog(String name){  //输入的是String ，输出的是Dog 实例
        this.name = name;
    }
    public Dog(){
    }
}
public class MethodReferenceDemo {
    public static void main(String[] args) {
        // 方法引用 System.out::println ;;当输入和输出都是s 的时候就可以简写成这样。
        Consumer<String> consumer = System.out::println;
        consumer.accept("consumer test");

        // 静态方法的方法引用 ;;这里消费的是Dog,等号右边我们用的是类名和 静态方法名
        // Dog::bark 就是方法引用，因为它是有输入没有return，和Consumer<String> 类型一模一样
        Consumer<Dog> dogConsumer = Dog::bark;
        Dog dog = new Dog("哈士奇");
        // 指定你要消费哪个 对象。
        dogConsumer.accept(dog);

        // 方法引用 有好处的这样就不用new 一个实例调用方法，是写一个匿名接口直接引用里面的方法。
        //非静态方法，使用对象实例的方法引用  (实例::方法名)
        Function<Integer,Integer> function = dog::eat;
        // dog = null ;  如果这里吧dog实例改成null 也不会报错的，因为java 传的值，用的是副本那份，和“原版” 无关的。
        System.out.println("还剩下："+function.apply(1));

        // 这里有两个输入一个输出,BiFunction代表有两个入参数
        // 使用类名 来方法引用，因为第一个参数是Dog,其实就是指针this，和上面实例名::方法其实是一样的。
        BiFunction<Dog,Integer,Integer> eatFunction = Dog::eat;
        System.out.println("还剩下："+eatFunction.apply(dog,2)+"斤");

        //构造函数的方法引用
        Supplier<Dog> supplier = Dog::new;
        System.out.println("创建了新对象："+supplier.get());

        //带参数的构造函数 方法引用

        Function<String,Dog> function1 = Dog::new;
        System.out.println("创建新对象："+function1.apply("哈士奇").toString());
    }
}
